/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#ifndef __XOS_BOX_PROPERTY_PROPERTY_TEMPLATE_H__
#define __XOS_BOX_PROPERTY_PROPERTY_TEMPLATE_H__

#include "../tools/head.h"
#include "../impl/head.h"

//////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_box
{
    
    class i_variant;

    template< typename BASE_INTERFACE, typename KEY, typename T >
    class property_template : public BASE_INTERFACE
    {
    public:
        typedef typename std::unordered_map< KEY, i_variant* > VT_MAP;
        typedef typename VT_MAP::iterator VT_ITER;

    public:
        property_template()
        {
            init_data();
        }
        ~property_template()
        {
        }

    protected:
        VT_ITER m_id_iter;
        VT_MAP m_id_map;

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        // id index get
        // 
    public:
        const char * str( T nId, char * lpszValue, int nBufSize, int * lpnSizeNeeded )
        {
            i_variant * pV = vt( nId );
            const char * pR = 0;
            if( pV )
            {
                pR = pV->str( lpszValue, nBufSize, lpnSizeNeeded );
            }
            return pR;
        }

        xos::i_release * obj( T nId, xos::i_release ** ppv )
        {
            i_variant * pV = vt( nId );
            xos::i_release * pR = 0;
            if( pV )
            {
                pR = pV->obj( ppv );
            }
            return pR;
        }

        xos_box::i_list * list( T nId, xos_box::i_list ** ppv )
        {
            i_variant * pV = vt( nId );
            xos_box::i_list * pR = 0;
            if( pV )
            {
                pR = pV->list( ppv );
            }
            return pR;
        }

        i_int_property * int_prop( T nId, i_int_property ** ppv )
        {
            i_variant * pV = vt( nId );
            i_int_property * pR = 0;
            if( pV )
            {
                pR = pV->int_prop( ppv );
            }
            return pR;
        }

        i_str_property * str_prop( T nId, i_str_property ** ppv )
        {
            i_variant * pV = vt( nId );
            i_str_property * pR = 0;
            if( pV )
            {
                pR = pV->str_prop( ppv );
            }
            return pR;
        }

        v_create fun( T nId, v_create * pv )
        {
            i_variant * pV = vt( nId );
            v_create pR = 0;
            if( pV )
            {
                pR = pV->fun( pv );
            }
            return pR;
        }

        double dbl( T nId, double * lpdValue )
        {
            i_variant * pV = vt( nId );
            double dl = 0.0;
            if( pV )
            {
                dl = pV->dbl( lpdValue );
            }
            return dl;
        }

        float flt( T nId, float * lpfValue )
        {
            i_variant * pV = vt( nId );
            float ft = 0.0f;
            if( pV )
            {
                ft = pV->flt( lpfValue );
            }
            return ft;
        }

        int32_t i32( T nId, int32_t * lpnValue )
        {
            i_variant * pV = vt( nId );
            int32_t i = 0;
            if( pV )
            {
                i = pV->i32( lpnValue );
            }
            return i;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        // id index set
        // 

        int set( T nId, const char * lpszValue )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpszValue );
            return 0;
        }

        int set_obj( T nId, xos::i_release * pv, bool bAutoRelease )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_obj( pv, bAutoRelease );
            return 0;
        }

        int set_list( T nId, xos_box::i_list * pv, bool bAutoRelease )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_list( pv, bAutoRelease );
            return 0;
        }

        int set_int_prop( T nId, i_int_property * pv, bool bAutoRelease )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_int_prop( pv, bAutoRelease );
            return 0;
        }

        int set_str_prop( T nId, i_str_property * pv, bool bAutoRelease )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_str_prop( pv, bAutoRelease );
            return 0;
        }

        int set( T nId, i_variant * pv )
        {
            i_variant * pVt = remove( nId );
            xos_stl::release_interface( pVt );
            m_id_map[nId] = pv;
            return 0;
        }

        int set( T nId, v_create pv )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( pv );
            return 0;
        }

        int set( T nId, double value )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( value );
            return 0;
        }

        int set( T nId, float value )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( value );
            return 0;
        }

        int set( T nId, int32_t value )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( value );
            return 0;
        }

        int set( T nId, uint64_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, int64_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, uint32_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, int32_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, uint16_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, int16_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set_u8( T nId, uint8_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_u8( lpRef );
            return 0;
        }

        int set_i8( T nId, int8_t * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_i8( lpRef );
            return 0;
        }

        int set_char_array( T nId, char * lpRef, int nBufSize )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_char_array( lpRef, nBufSize );
            return 0;
        }

        int set_bin( T nId, char * lpRef, int nBufSize )
        {
            i_variant * pVt = get( nId, true );
            pVt->set_bin( lpRef, nBufSize );
            return 0;
        }

        int set( T nId, double * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, float * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        int set( T nId, bool * lpRef )
        {
            i_variant * pVt = get( nId, true );
            pVt->set( lpRef );
            return 0;
        }

        uint64_t * u64_ptr( T nId, uint64_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            uint64_t * pRet = 0;
            if( pV )
            {
                pRet = pV->u64_ptr( lppRet );
            }
            return pRet;
        }

        int64_t * i64_ptr( T nId, int64_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            int64_t * pRet = 0;
            if( pV )
            {
                pRet = pV->i64_ptr( lppRet );
            }
            return pRet;
        }

        uint32_t * u32_ptr( T nId, uint32_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            uint32_t * pRet = 0;
            if( pV )
            {
                pRet = pV->u32_ptr( lppRet );
            }
            return pRet;
        }

        int32_t * i32_ptr( T nId, int32_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            int32_t * pRet = 0;
            if( pV )
            {
                pRet = pV->i32_ptr( lppRet );
            }
            return pRet;
        }

        uint16_t * u16_ptr( T nId, uint16_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            uint16_t * pRet = 0;
            if( pV )
            {
                pRet = pV->u16_ptr( lppRet );
            }
            return pRet;
        }

        int16_t * i16_ptr( T nId, int16_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            int16_t * pRet = 0;
            if( pV )
            {
                pRet = pV->i16_ptr( lppRet );
            }
            return pRet;
        }

        uint8_t * u8_ptr( T nId, uint8_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            uint8_t * pRet = 0;
            if( pV )
            {
                pRet = pV->u8_ptr( lppRet );
            }
            return pRet;
        }

        int8_t * i8_ptr( T nId, int8_t ** lppRet )
        {
            i_variant * pV = vt( nId );
            int8_t * pRet = 0;
            if( pV )
            {
                pRet = pV->i8_ptr( lppRet );
            }
            return pRet;
        }

        char * char_array( T nId, char ** lppRet, int * lpnSize, int * lpnLen )
        {
            i_variant * pV = vt( nId );
            char * pRet = 0;
            if( pV )
            {
                pRet = pV->char_array( lppRet, lpnSize, lpnLen );
            }
            return pRet;
        }

        char * bin_ptr( T nId, char ** lppRet, int * lpnSize, int * lpnLen )
        {
            i_variant * pV = vt( nId );
            char * pRet = 0;
            if( pV )
            {
                pRet = pV->bin_ptr( lppRet, lpnSize, lpnLen );
            }
            return pRet;
        }

        double * dbl_ptr( T nId, double ** lppRet )
        {
            i_variant * pV = vt( nId );
            double * pRet = 0;
            if( pV )
            {
                pRet = pV->dbl_ptr( lppRet );
            }
            return pRet;
        }

        float * flt_ptr( T nId, float ** lppRet )
        {
            i_variant * pV = vt( nId );
            float * pRet = 0;
            if( pV )
            {
                pRet = pV->flt_ptr( lppRet );
            }
            return pRet;
        }

        bool * bool_ptr( T nId, bool ** lppRet )
        {
            i_variant * pV = vt( nId );
            bool * pRet = 0;
            if( pV )
            {
                pRet = pV->bool_ptr( lppRet );
            }
            return pRet;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        // id index helper
        // 

        i_variant * remove( T nId )
        {
            VT_ITER iter = m_id_map.find( nId );
            i_variant * pVt = 0;
            if( iter != m_id_map.end() )
            {
                pVt = iter->second;
                m_id_map.erase( iter );
            }
            return pVt;
        }

        i_variant * vt( T nId )
        {
            i_variant * pVt = get( nId, false );
            return pVt;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        // other helper
        // 

        int reset()
        {
            int ret = 0;
            m_id_iter = m_id_map.begin();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 

        int release_all()
        {
            int ret = 0;
            for( VT_ITER iter = m_id_map.begin(); iter != m_id_map.end(); ++iter )
            {
                i_variant * p = iter->second;
                p->release();
            }
            m_id_map.clear();
            return ret;
        }

        int size()
        {
            int ret = 0;
            ret = (int)m_id_map.size();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
    protected:
        i_variant * get( T nId, bool bCreate )
        {
            VT_ITER iter = m_id_map.find( nId );
            i_variant * pV = 0;
            if( iter != m_id_map.end() )
            {
                pV = iter->second;
            }
            else if( bCreate )
            {
                pV = mgr::container()->box()->vt();
                m_id_map[nId] = pV;
            }
            return pV;
        }

        int init_data()
        {
            int ret = 0;
            m_id_iter = m_id_map.end();
            return ret;
        }

        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
    public:
        int init()
        {
            int ret = 0;
            return ret;
        }
        int term()
        {
            int ret = 0;
            release_all();
            init_data();
            return ret;
        }

    };

} // xos_box

#endif // __XOS_BOX_PROPERTY_PROPERTY_TEMPLATE_H__
